/*
 * Copyright (C) 2012 Jonathan St-Michel <jonathan@abiwebz.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * QUAND        QUI     QUOI
 * ============================================================================
 * 2012-05-16   JSM     Ajout de la fonction dans le projet
 */

package org.abiwebz.platform;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.abiwebz.platform.util.ErrorHandling;
import org.abiwebz.platform.util.ModuleLoader;
import org.abiwebz.platform.view.IView;
import org.abiwebz.platform.window.ApplicationWindow;

/**
 * Classe principale de l'application, celle-ci permet de récupérer diverses
 * information en utilisant la technique du "singleton". 
 * 
 * Avant de charger la fenêtre de l'application la configuration est établie 
 * dans cette classe.
 * 
 * @author Jonathan St-Michel<jonathan@abiwebz.net>
 * @version 1
 */
public class Application {

    /********* SWITCHES ******************************************************/
    public static boolean showErrorCodeSwitch = false;
    public static String classname = "";
    public static String modules = "";
    public static String theme = "default";
    
    
    /********* SINGLETON *****************************************************/
    protected static ApplicationPlugin singletonInstance = null;
    
    /**
     * Retourner une copie de l'application pour récupérer les informations
     * répertoriées au démarrage de celle-ci.
     * 
     * @return Une copie de l'application
     */
    public static ApplicationPlugin getInstance(){
        return Application.singletonInstance;
    }
    
    /**
     * Créer selon la technique du "singleton" l'instance de la classe 
     * Application qui pourra être récupérée de n'importe où.
     * 
     * @return Une copie de la nouvelle application
     */
    public static ApplicationPlugin newInstance(String classname) {
        try {

            Application.singletonInstance = (ApplicationPlugin) ModuleLoader.getInstance().loadClass(classname).newInstance();
            return Application.getInstance(); //TODO Vérifier si c'est plus éfficace de passé par la variable statique

        } catch (IllegalAccessException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex){
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /*************************************************************************/
    
    /**
     * Exécutée au démarrage de l'application par le système d'exploitation.
     * 
     * La fonction reçoit les paramètres sous forme de "switches" ainsi que les
     * chemin d'accès utilisé pour le programme (module) principal. 
     * L'application démarre lorsque les bons paramètres ainsi que les 
     * "switches" sont utilisées.
     * 
     * @param args Les arguments en provenance de la ligne de commande
     */
    public static void main(String[] args) {
        findSwitches(args);
        
        //Configurer les messages d'erreur de la platform
        if(ErrorHandling.newInstance() != null){
            ErrorHandling.getInstance().addDefinitions("platform", Application.class.getResourceAsStream("messages.properties"));
        }
        
        //Vérifier la classe application
        if(Application.classname.equals("")){
            //TODO Générer une erreur
            ErrorHandling.getInstance().error("0xA00", "platform");
            System.exit(1);
        }
        
        //Vérifier le chemin des modules
        if(Application.modules.equals("")){
            //TODO Gérérer une erreur
            ErrorHandling.getInstance().error("0xA00", "platform");
            System.exit(1);
        }
        
        //Démarrer l'application en démarrant un Thread spécifique à l'UI
        SwingUtilities.invokeLater(new Runnable(){

            @Override
            public void run() {
                //Charger le classloader
                ModuleLoader.newInstance(new File(Application.modules));

                //Créer l'application en mémoire
                ApplicationWindow window;
                ApplicationPlugin app = Application.newInstance(Application.classname);
                if(app != null){
                    //TODO Améliorer ce call
                    //Charger les modules
                    
                    //Charger l'application
                    //Utiliser le LAF pour les bordures des Frames
                    JFrame.setDefaultLookAndFeelDecorated(true);
                    //Configuration à l'aide des xmls récupérés
                    app.configure();
                    //Configurer la vue utilisée par l'application
                    IView view = app.configureView();
                    //Configuration de l'écran principale
                    window = app.getWindow();
                    window.getRibbonManager().generate();
                    window.setView(view);
                    //Démarrage de l'application - dernières exécution 
                    //spécifiques à l'application
                    if(app.start()){
                        //Afficher l'écran principale
                        window.setVisible(true);
                    }
                    else{
                        //L'application n'a pas démarrer, la platforme peut s'éteindre
                        Application.quit();
                    }
                }
                else{
                    ErrorHandling.getInstance().error("0xA01", "platform");
                    Application.quit();
                }
            }
            
        });
        
    }
    
    /**
     * Permet de récupérer les «switches» pour activer/désactiver des fonctions
     * lors de l'utilisation de l'application. La liste des «switches» est la 
     * suivante :
     * 
     * -e       Activer l'affichage du code d'erreur dans les messages
     * -main    Définit la classe d'application (index suivant)
     * -modules Définit le répertoire contenant les plugins/modules/app
     * 
     * @param args Les arguments en provenance de la ligne de commande
     */
    private static void findSwitches(String[] args) {
        String lowerString;
        boolean nextIsClassname = false;
        boolean nextIsModuleFolder = false;
        
        for(String a : args){
            if(nextIsClassname){
                Application.classname = a;
            }
            if(nextIsModuleFolder){
                Application.modules = a;
            }
            nextIsClassname = false;
            nextIsModuleFolder = false;
            lowerString = a.toLowerCase();
            
            //Vérifier la «switch» -e
            if(lowerString.equals("-e")){
                Application.showErrorCodeSwitch = true;
            }
            
            //Vérifier la «switch» -main
            if(lowerString.equals("-main")){
                nextIsClassname = true;
            }
            
            //Vérifier la «switch» -modules
            if(lowerString.equals("-modules")){
                nextIsModuleFolder = true;
            }
        }
    }
    
    /**
     * Fonction standard pour quitter la platforme ainsi que l'application.
     * 
     */
    public static void quit(){
        System.exit(0);
    }
    
}
